package com.rede.didiok.user.service.impl;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rede.didiok.common.constant.conf.MessageConf;
import com.rede.didiok.common.constant.conf.RedisConf;
import com.rede.didiok.common.constant.conf.SQLConf;
import com.rede.didiok.common.constant.conf.SysConf;
import com.rede.didiok.common.constant.conf.base.BaseSQLConf;
import com.rede.didiok.common.constant.global.Constants;
import com.rede.didiok.common.constant.global.ErrorCode;
import com.rede.didiok.common.dto.admin.AdminDto;
import com.rede.didiok.common.dto.community.MomentCommentDto;
import com.rede.didiok.common.dto.community.UserMomentDto;
import com.rede.didiok.common.dto.rank.MemberCommentDto;
import com.rede.didiok.common.dto.rank.RankMemberDto;
import com.rede.didiok.common.dto.user.*;
import com.rede.didiok.common.enums.*;
import com.rede.didiok.common.exception.exceptionType.FeignException;
import com.rede.didiok.common.exception.exceptionType.InsertException;
import com.rede.didiok.common.exception.exceptionType.QueryException;
import com.rede.didiok.common.exception.exceptionType.UpdateException;
import com.rede.didiok.common.feign.AdminFeignClient;
import com.rede.didiok.common.feign.CommunityFeignClient;
import com.rede.didiok.common.feign.FileFeignClient;
import com.rede.didiok.common.feign.RankFeignClient;
import com.rede.didiok.common.holder.RequestHolder;
import com.rede.didiok.common.schema.ChatResponse.ChatGPTSetting;
import com.rede.didiok.common.utils.*;
import com.rede.didiok.common.utils.business.DomainEventUtil;
import com.rede.didiok.common.utils.business.FileFeignUtil;
import com.rede.didiok.common.utils.business.WebUtil;
import com.rede.didiok.user.dao.UserDao;
import com.rede.didiok.user.dao.UserWatchDao;
import com.rede.didiok.user.entity.UserAccountEntity;
import com.rede.didiok.user.entity.UserEntity;
import com.rede.didiok.user.entity.WebVisitEntity;
import com.rede.didiok.user.exception.MobileExsitException;
import com.rede.didiok.user.exception.UserNameExistException;
import com.rede.didiok.user.service.*;

@Slf4j
@Service("userService")
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Resource
    private UserDao userDao;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private WebUtil webUtil;
    @Autowired
    private FileFeignUtil fileFeignUtil;

    @Resource
    CommunityFeignClient communityFeignClient;
    @Resource
    RankFeignClient rankFeignClient;
    @Resource
    private NoticeService noticeService;
    @Resource
    private UserWatchService userWatchService;
    @Resource
    private UserWatchDao userWatchDao;
    @Resource
    private AdminFeignClient adminFeignClient;
    @Resource
    private FileFeignClient fileFeignClient;
    @Resource
    private WebVisitService webVisitService;
    @Resource
    private CreditsLogService creditsLogService;
    @Resource
    private UserAccountService userAccountService;
//    @Resource
//    private UserEquityRecordService userEquityRecordService;
    @Value(value = "${data.webSite.url}")
    private String webSiteUrl;
    @Resource
    private DomainEventUtil domainEventUtil;


    /***************************** didiok-admin:start **************************/
    // region  didiok-admin

    /**
     * 获取用户数
     *
     * @param status
     * @return
     */
    @Override
    public Integer getUserCount(int status) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(BaseSQLConf.STATUS, status);
        return this.count(queryWrapper);
    }

    @Override
    public Map<String, UserEntity> getUserAvatarMapByIds(List<String> ids) {
        Map<String, UserEntity> userMap = new HashMap<>();
        if (ids.size() == 0) {
            return userMap;
        }
        List<UserEntity> userList = this.getUserListByIds(ids);
        this.setUserAvatar(userList);
        userList = this.convertUserList(userList);

        for (UserEntity user : userList) {
            userMap.put(user.getUid(), user);
        }
        return userMap;
    }

    @Override
    public Map<String, UserEntity> listUserNameAndAvatarByUids(List<String> ids) {
        Map<String, UserEntity> userMap = new HashMap<>();
        if (ids.size() == 0) {
            return userMap;
        }
        List<UserEntity> userList = userDao.listUserNameAndAvatarByUids(ids);

        for (UserEntity user : userList) {
            userMap.put(user.getUid(), user);
        }
        return userMap;
    }

    /**
     * 根据userUids 获取 开启邮件通知 的用户
     *
     * @param userUids
     * @return
     */
    @Override
    public List<UserEntity> listUserStartEmailNotification(Set<String> userUids) {
        return this.list(
                new LambdaQueryWrapper<UserEntity>()
                        .in(UserEntity::getUid, userUids)
                        .eq(UserEntity::getStartEmailNotification, 1)
                        .isNotNull(UserEntity::getEmail)
                        .apply(" email !='' ")
        );
    }

    @Override
    public IPage<UserEntity> getPageList(UserDto userDto) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        // 查询用户名
        if (StringUtils.isNotEmpty(userDto.getKeyword()) && !StringUtils.isEmpty(userDto.getKeyword().trim())) {
            String keyword = userDto.getKeyword().trim();
            queryWrapper.like(SQLConf.USER_NAME, keyword).or().like(SQLConf.NICKNAME, keyword).or().like(SQLConf.UID, keyword);
        }
        if (StringUtils.isNotEmpty(userDto.getSource()) && !StringUtils.isEmpty(userDto.getSource().trim())) {
            queryWrapper.eq(SQLConf.SOURCE, userDto.getSource().trim());
        }
        if (userDto.getCommentStatus() != null) {
            queryWrapper.eq(SQLConf.COMMENT_STATUS, userDto.getCommentStatus());
        }
        if (userDto.getUserTag() != null) {
            queryWrapper.eq(SQLConf.USER_TAG, userDto.getUserTag());
        }
        if (userDto.getUserUidList() != null && userDto.getUserUidList().size() > 0) {
            queryWrapper.in(SQLConf.UID, userDto.getUserUidList());
        }
        if (userDto.getNeedEmail() != null && userDto.getNeedEmail()) {
            queryWrapper.isNotNull(SQLConf.EMAIL);
        }

        if (StringUtils.isNotEmpty(userDto.getOrderByAscColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(userDto.getOrderByAscColumn())).toString();
            queryWrapper.orderByAsc(column);
        } else if (StringUtils.isNotEmpty(userDto.getOrderByDescColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(userDto.getOrderByDescColumn())).toString();
            queryWrapper.orderByDesc(column);
        } else {
            queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
        }

        queryWrapper.select(UserEntity.class, i -> !i.getProperty().equals(SQLConf.PASSWORD));
        Page<UserEntity> page = new Page<>();
        page.setCurrent(userDto.getCurrentPage());
        page.setSize(userDto.getPageSize());
        queryWrapper.ne(SQLConf.STATUS, StatusEnum.DISABLED);
        IPage<UserEntity> pageList = this.page(page, queryWrapper);
        List<UserEntity> list = pageList.getRecords();
        // 设置用户头像
        if (userDto.getNeedAvatar() == null || userDto.getNeedAvatar()) {
            this.setUserAvatar(list);
        }
        pageList.setRecords(list);
        return pageList;
    }

    @Override
    public List<UserEntity> getUserPageRecords(UserDto userDto) {
        return getPageList(userDto).getRecords();
    }

    @Override
    public String addUser(UserDto userDto) {
        UserEntity user = new UserEntity();
        // 字段拷贝【将userVO中的内容拷贝至user】
        BeanUtils.copyProperties(userDto, user, SysConf.STATUS);
        String defaultPassword = userDto.getDefaultPassword();
        if(StringUtils.isEmpty(defaultPassword)) {
            defaultPassword = adminFeignClient.getSysParamsValueByKey(SysConf.SYS_DEFAULT_PASSWORD);
        }
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPassword(encoder.encode(defaultPassword));
        user.setSource("DIDIOK");
        user.insert();
        return ResultUtil.successWithMessage(MessageConf.INSERT_SUCCESS);
    }

    @Override
    public String editUser(UserDto userDto) {
        UserEntity user = this.getById(userDto.getUid());
        user.setUserName(userDto.getUserName());
        user.setEmail(userDto.getEmail());
        user.setStartEmailNotification(userDto.getStartEmailNotification());
        user.setOccupation(userDto.getOccupation());
        user.setGender(userDto.getGender());
        user.setQqNumber(userDto.getQqNumber());
        user.setSummary(userDto.getSummary());
        user.setBirthday(userDto.getBirthday());
        user.setAvatar(userDto.getAvatar());
        user.setNickname(userDto.getNickname());
        user.setUserTag(userDto.getUserTag());
        user.setCommentStatus(userDto.getCommentStatus());
        user.setUpdateTime(new Date());
        user.setStatus(userDto.getStatus());
        user.updateById();

        // 编辑用户时，删除用户的评论状态
        redisUtil.delete(RedisConf.USER_ACTIVE_STATUS + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + user.getUid());

        return ResultUtil.successWithMessage(MessageConf.UPDATE_SUCCESS);
    }

    @Override
    public String deleteUser(UserDto userDto) {
        UserEntity user = this.getById(userDto.getUid());
        user.setStatus(StatusEnum.DISABLED);
        user.setUpdateTime(new Date());
        user.updateById();
        return ResultUtil.successWithMessage(MessageConf.DELETE_SUCCESS);
    }

    @Override
    public String resetUserPassword(UserDto userDto) {
        String defaultPassword = userDto.getDefaultPassword();
        if(StringUtils.isEmpty(defaultPassword)) {
            defaultPassword = adminFeignClient.getSysParamsValueByKey(SysConf.SYS_DEFAULT_PASSWORD);
        }
        UserEntity user = this.getById(userDto.getUid());
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPassword(encoder.encode(defaultPassword));
        user.setUpdateTime(new Date());
        user.updateById();
        return ResultUtil.successWithMessage(MessageConf.OPERATION_SUCCESS);
    }

    @Override
    public String flushUserAccount() {
        // 查询出账号非蘑菇注册的账号
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        queryWrapper.ne(SQLConf.SOURCE, "DIDIOK");
        List<UserEntity> userList = this.list(queryWrapper);
        Set<String> hashSet = new HashSet<>();

        for (UserEntity user : userList) {
            Boolean isContains = hashSet.contains(user.getSocialUid());
            // 未包含过，进行处理
            if (!isContains) {
                hashSet.add(user.getSocialUid());

                UserAccountEntity userAccount = new UserAccountEntity();
                userAccount.setCreateUserUid(user.getUid());
                userAccount.setSocialUid(user.getSocialUid());
                userAccount.setCreateUserName(user.getUserName());
                userAccount.setNickname(user.getNickname());
                userAccount.setSource(user.getSource());
                userAccount.setBindTime(user.getCreateTime());
                userAccount.setAvatar(user.getAvatar());
                userAccount.setEmail(user.getEmail());
                userAccount.setGender(user.getGender());
                userAccount.setSummary(user.getSummary());
                userAccount.insert();
            } else {
                // 已经存在，直接跳过
                continue;
            }
        }
        return ResultUtil.successWithMessage(MessageConf.INSERT_SUCCESS);
    }

    // endregion
    /***************************** didiok-admin:end **************************/



    /***************************** didiok-web:start **************************/
    // region didiok-web

    /**
     * 根据用户uid列表查询用户
     *
     * @param uidList
     * @return
     */
    @Override
    public List<UserEntity> listUserByUids(List<String> uidList) {
        return this.listByIds(uidList);
    }

    /**
     * 关闭邮件通知
     *
     * @param userUid
     * @return
     */
    @Override
    public UserEntity closeEmailNotificationById(String userUid) {
        UserEntity user = this.getById(userUid);
        if (user == null) {
            ResultUtil.errorWithMessage(MessageConf.OPERATION_FAIL);
        }
        user.setStartEmailNotification(0);
        user.updateById();
        return user;
    }

    @Override
    public IPage<UserEntity> getUserTopN(UserDto userVO) {
        // 首页展示的topN
        String userListJson = redisUtil.get(RedisConf.INDEX_TOP_N_USER);
        String userListTotalJson = redisUtil.get(RedisConf.INDEX_TOP_N_USER_TOTAL);
        String topN = adminFeignClient.getSysParamsValueByKey(SysConf.USER_TOP_N);
        String topNJson = redisUtil.get(RedisConf.SYSTEM_PARAMS + RedisConf.SEGMENTATION + SysConf.USER_TOP_N);
        if (userVO.getCurrentPage() == Constants.NUM_ONE && StringUtils.isNotEmpty(userListJson) && StringUtils.isNotEmpty(userListTotalJson) && StringUtils.isNotEmpty(topNJson) && !userVO.getRefresh()) {
            List<UserEntity> userList = (List<UserEntity>) JsonUtils.jsonArrayToArrayList(userListJson);
            Integer total = Integer.valueOf(userListTotalJson);
            IPage<UserEntity> page = new Page();
            page.setRecords(userList);
            page.setTotal(total);
            page.setSize(Constants.NUM_TEN);
            page.setCurrent(Constants.NUM_ONE);
            return page;
        }
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        Page<UserEntity> userPage = new Page<>();
        userPage.setCurrent(userVO.getCurrentPage());
        userPage.setSize(Constants.NUM_TEN);
        queryWrapper.orderByDesc(SQLConf.EXP_VALUE);
        IPage<UserEntity> userPageList = this.page(userPage, queryWrapper);

        // 判断页的大小是否超过限定
        int topNum = Integer.valueOf(topN);
        if (userPageList.getTotal() > topNum) {
            userPageList.setTotal(topNum);
        }

        List<UserEntity> userList = userPageList.getRecords();
        if (userList.size() > 0) {
            // 获取用户头像
            this.setUserAvatar(userList);
            // 过滤用户敏感信息
            userList = this.convertUserList(userList);
            // 设置用户信息基本信息
            this.setUserPublishInfo(userList);
        }
        userPageList.setRecords(userList);
        // 只缓存第一页的内容
        if (userList.size() > 0 && userPageList.getCurrent() == 1) {
            redisUtil.setEx(RedisConf.INDEX_TOP_N_USER, JsonUtils.objectToJson(userList), 10, TimeUnit.MINUTES);
            redisUtil.setEx(RedisConf.INDEX_TOP_N_USER_TOTAL, JsonUtils.objectToJson(userPageList.getTotal()), 10, TimeUnit.MINUTES);
        }
        return userPageList;
    }

    /**
     * 通过用户名查询相关用户信息
     *
     * @param keywords
     * @param currentPage
     * @param pageSize
     * @return
     */
    public Map<String, Object> getByUser(String keywords, Long currentPage, Long pageSize) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        Page<UserEntity> page = new Page<>();
        page.setCurrent(currentPage);
        page.setSize(pageSize);
        queryWrapper.and(wrapper -> wrapper.like(SQLConf.NICKNAME, keywords).or().like(SQLConf.SUMMARY, keywords).or().like("occupation", keywords));
        queryWrapper.like(SQLConf.NICKNAME, keywords);
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
        IPage<UserEntity> pageList = this.page(page, queryWrapper);
        List<UserEntity> users = pageList.getRecords();

        // 敏感信息过滤
        users = this.convertUserList(users);

        List<String> userUids = users.stream().map(UserEntity::getUid).collect(Collectors.toList());
        R rankMemberResult = rankFeignClient.getUsersRankMemberCountByUserIds(userUids);
        List<Map<String, String>> rankMemberList;
        if (rankMemberResult.getCode() == 0) {
            rankMemberList = rankMemberResult.getData(new TypeReference<List<Map<String, String>>>(){});
        }else {
            // 获取异常信息
            throw new FeignException("feign调用异常（根据用户列表ID  查询各用户发表博客数）：失败啦");
        }
        Map<String, String> rankMemberMap = webUtil.listCovertMap(rankMemberList);

        R memberCommentResult = rankFeignClient.getCommentCountByUserIds(userUids);
        List<Map<String, String>> memberCommentList;
        if (memberCommentResult.getCode() == 0) {
            memberCommentList = memberCommentResult.getData(new TypeReference<List<Map<String, String>>>(){});
        }else {
            // 获取异常信息
            throw new FeignException("feign调用异常（根据用户列表ID  查询各用户评论数）：失败啦");
        }
        Map<String, String> memberCommentMap = webUtil.listCovertMap(memberCommentList);

        List<Map<String, String>> userWatchList = userWatchDao.getUserWatchCountByUserId(userUids);
        Map<String, String> userWatchMap = webUtil.listCovertMap(userWatchList);

        R userMomentResult = communityFeignClient.getUserMomentCountByUserIds(userUids);
        List<Map<String, String>> userMomentList;
        if (userMomentResult.getCode() == 0) {
            userMomentList = userMomentResult.getData(new TypeReference<List<Map<String, String>>>(){});
        }else {
            // 获取异常信息
            throw new FeignException("feign调用异常（根据用户列表ID  查询各用户发表博客数）：失败啦");
        }
        Map<String, String> userMomentMap = webUtil.listCovertMap(userMomentList);

        R momentCommentResult = communityFeignClient.getCommentCountByUserIds(userUids);
        List<Map<String, String>> momentCommentList;
        if (momentCommentResult.getCode() == 0) {
            momentCommentList = momentCommentResult.getData(new TypeReference<List<Map<String, String>>>(){});
        }else {
            // 获取异常信息
            throw new FeignException("feign调用异常（根据用户列表ID  查询各用户评论数）：失败啦");
        }
        Map<String, String> momentCommentMap = webUtil.listCovertMap(momentCommentList);


        for (UserEntity user : users) {
            // 通过头像uid获取图片
            String pictureList = fileFeignClient.getPicture(user.getAvatar(), SysConf.FILE_SEGMENTATION);
            List<String> photoList = webUtil.getPicture(pictureList);
            Map<String, Object> picMap = (Map<String, Object>) JsonUtils.jsonToObject(pictureList, Map.class);

            // 判断该用户是否含有头像信息
            if (SysConf.SUCCESS.equals(picMap.get(SysConf.CODE)) && photoList.size() > 0) {
                user.setPhotoUrl(photoList.get(0));
            }

            //  设置博客发表数
            String memberVisitCountJson = redisUtil.get(RedisConf.RANK_MEMBER_PUBLISH_COUNT + Constants.SYMBOL_COLON + user.getUid());
            if (StringUtils.isNotEmpty(memberVisitCountJson)) {
                user.setRankMemberPublishCount(Integer.valueOf(memberVisitCountJson));
            } else {
                Integer blogPublishCount = Integer.valueOf(rankMemberMap.get(user.getUid()) != null ? rankMemberMap.get(user.getUid()) : "0");
                user.setRankMemberPublishCount(blogPublishCount);
                redisUtil.setEx(RedisConf.RANK_MEMBER_PUBLISH_COUNT + Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(blogPublishCount), 10, TimeUnit.MINUTES);
            }

            // 设置榜单成员评论数
            String memberCommentPublishCountJson = redisUtil.get(RedisConf.MEMBER_COMMENT_PUBLISH_COUNT + Constants.SYMBOL_COLON + user.getUid());
            if (StringUtils.isNotBlank(memberCommentPublishCountJson)) {
                user.setMemberCommentPublishCount(Integer.valueOf(memberCommentPublishCountJson));
            } else {
                Integer commentPublishCount = Integer.valueOf(memberCommentMap.get(user.getUid()) != null ? memberCommentMap.get(user.getUid()) : "0");
                user.setMemberCommentPublishCount(commentPublishCount);
                redisUtil.setEx(RedisConf.MEMBER_COMMENT_PUBLISH_COUNT + Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(commentPublishCount), 10, TimeUnit.MINUTES);
            }

            // 设置用户动态评论数
            String momentCommentPublishCountJson = redisUtil.get(RedisConf.MOMENT_COMMENT_PUBLISH_COUNT + Constants.SYMBOL_COLON + user.getUid());
            if (StringUtils.isNotBlank(momentCommentPublishCountJson)) {
                user.setMomentCommentPublishCount(Integer.valueOf(momentCommentPublishCountJson));
            } else {
                Integer commentPublishCount = Integer.valueOf(momentCommentMap.get(user.getUid()) != null ? momentCommentMap.get(user.getUid()) : "0");
                user.setMomentCommentPublishCount(commentPublishCount);
                redisUtil.setEx(RedisConf.MOMENT_COMMENT_PUBLISH_COUNT + Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(commentPublishCount), 10, TimeUnit.MINUTES);
            }

            // 设置关注数
            String userWatchCountJson = redisUtil.get(RedisConf.USER_WATCH_COUNT + Constants.SYMBOL_COLON + user.getUid());
            if (StringUtils.isNotBlank(userWatchCountJson)) {
                user.setPraiseCount(Integer.valueOf(userWatchCountJson));
            } else {
                Integer watchCount = Integer.valueOf(userWatchMap.get(user.getUid()) != null ? userWatchMap.get(user.getUid()) : "0");
                user.setPraiseCount(watchCount);
                redisUtil.setEx(RedisConf.USER_WATCH_COUNT + Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(watchCount), 10, TimeUnit.MINUTES);
            }

            //设置是否关注状态
            UserWatchDto userWatchVO = new UserWatchDto();
            userWatchVO.setToUserUid(user.getUid());
            Integer isWatch = userWatchService.checkCurrentUserWatch(userWatchVO);
            if (isWatch == 0) {
                //未关注
                user.setUserWatchStatus(0);
            } else if (isWatch == 1) {
                //单项关注
                user.setUserWatchStatus(1);
            } else {
                //互相关注
                user.setUserWatchStatus(2);
            }

            //设置动态发布数
            String userMomentCountJson = redisUtil.get(RedisConf.USER_MOMENT_COUNT + Constants.SYMBOL_COLON + user.getUid());
            if (StringUtils.isNotBlank(userMomentCountJson)) {
                user.setUserMomentCount(Integer.valueOf(userMomentCountJson));
            } else {
                Integer momentCount = Integer.valueOf(userMomentMap.get(user.getUid()) != null ? userMomentMap.get(user.getUid()) : "0");
                user.setUserMomentCount(momentCount);
                redisUtil.setEx(RedisConf.USER_MOMENT_COUNT + Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(momentCount), 10, TimeUnit.MINUTES);
            }

        }

        Map<String, Object> map = new HashMap<>();
        // 返回总记录数
        map.put(SysConf.TOTAL, pageList.getTotal());
        // 返回总页数
        map.put(SysConf.TOTAL_PAGE, pageList.getPages());
        // 返回当前页大小
        map.put(SysConf.PAGE_SIZE, pageList.getSize());
        // 返回当前页
        map.put(SysConf.CURRENT_PAGE, pageList.getCurrent());
        // 返回数据
        map.put(SysConf.USER_LIST, users);
        return map;

    }

    @Override
    public UserEntity getUserBySourceAndSocialUid(String source, String uuid) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(BaseSQLConf.SOCIAL_UID, uuid).eq(BaseSQLConf.SOURCE, source);
        return this.getOne(queryWrapper);
    }

    @Override
    public List<UserEntity> getUserListAndAvatarByIds(Collection<String> ids) {
        List<UserEntity> userList = new ArrayList<>();
        if (ids == null || ids.size() == 0) {
            return userList;
        }
        Collection<UserEntity> userCollection = this.listByIds(ids);
        // 过滤用户敏感信息
        userCollection.forEach(item -> {
            userList.add(this.convertUser(item));
        });
        // 设置用户头像
        this.setUserAvatar(userList);

        return userList;
    }

    /**
     * 获取发表的文章数
     *
     * @param userUid
     * @return
     */
    @Override
    public Integer getRankMemberPublishCount(String userUid) {
        if (StringUtils.isEmpty(userUid)) {
            return 0;
        }
        String blogVisitCountJson = redisUtil.get(RedisConf.RANK_MEMBER_PUBLISH_COUNT + Constants.SYMBOL_COLON + userUid);
        if (StringUtils.isNotEmpty(blogVisitCountJson)) {
            return Integer.valueOf(blogVisitCountJson);
        }
        Integer rankMemberPublishCount = rankFeignClient.countRankMemberByUserUidAndSource(userUid, ContributeSourceEnum.USER_PUBLISH);
        return rankMemberPublishCount;
    }

    @Override
    public UserEntity getUserByUuidAndSource(String uuid, String source) {
        QueryWrapper<UserAccountEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.SOURCE, source);
        queryWrapper.eq(SQLConf.ACCOUNT_ID, uuid);
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        queryWrapper.last(SysConf.LIMIT_ONE);
        UserAccountEntity userAccount = userAccountService.getOne(queryWrapper);
        if (userAccount != null) {
            String userUid = userAccount.getCreateUserUid();
            return this.getById(userUid);
        }
        return null;
    }

    @Override
    public Integer getCurrentUserCredits(Boolean refresh) {
        Integer credits = 0;
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            return credits;
        }
        String creditsJson = redisUtil.get(RedisConf.USER_CREDITS + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + userUid);
        if (StringUtils.isNotEmpty(creditsJson) && !refresh) {
            return Integer.valueOf(creditsJson);
        }
        UserEntity user = this.getById(userUid);
        credits = user.getCredits();
        // 设置积分到redis中
        redisUtil.setEx(RedisConf.USER_CREDITS + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + userUid, JsonUtils.objectToJson(credits), 10, TimeUnit.MINUTES);
        return credits;
    }

    @Override
    public String updateCurrentUserBackgroundImage(UserDto userDto) {
        if (StringUtils.isNotEmpty(userDto.getBackgroundFileUid())) {
            String userUid = RequestHolder.getUserUid();
            if (StringUtils.isEmpty(userUid)) {
                throw new QueryException(Constants.USER_UID_EMPTY);
            }
            UserEntity user = this.getById(userUid);
            if (user != null) {
                user.setBackgroundFileUid(userDto.getBackgroundFileUid());
                user.updateById();
                return ResultUtil.successWithMessage(MessageConf.UPDATE_SUCCESS);
            }
        }
        return ResultUtil.errorWithMessage(MessageConf.UPDATE_FAIL);
    }

    @Override
    public List<UserEntity> convertUserList(Collection<UserEntity> userList) {
        List<UserEntity> resultUserList = new ArrayList<>();
        userList.forEach(item -> {
            resultUserList.add(convertUser(item));
        });
        return resultUserList;
    }

    /**
     * 查询积分总榜
     *
     * @return
     */
    @Override
    public List<UserEntity> getLeaderAll(Boolean refresh) {
        String rankUserListJson = redisUtil.get(RedisConf.TOP_LIST + Constants.SYMBOL_COLON + RedisConf.TOP_ALL_LIST);
        List<UserEntity> userList;
        if (StringUtils.isNotEmpty(rankUserListJson) && refresh) {
            userList = JsonUtils.jsonToList(rankUserListJson, UserEntity.class);
        } else {
            QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
            queryWrapper.orderByDesc(SQLConf.CREDITS);
            queryWrapper.last("limit 10");
            List<UserEntity> leaderAll = this.list(queryWrapper);
            // 过滤敏感信息
            this.setUserAvatar(leaderAll);
            userList = this.convertUserList(leaderAll);
            redisUtil.setEx(RedisConf.TOP_LIST + Constants.SYMBOL_COLON + RedisConf.TOP_ALL_LIST, JsonUtils.objectToJson(userList), 24, TimeUnit.HOURS);
        }
        return userList;
    }

    @Override
    public Long getUserAmount(String userUid) {
        UserEntity user = this.getById(userUid);
        if (user == null) {
            return 0L;
        }
        return user.getAmount();
    }

    @Override
    public UserEntity serRequestInfo(UserEntity user) {
        HttpServletRequest request = RequestHolder.getRequest();
        Map<String, String> map = IpUtils.getOsAndBrowserInfo(request);
        String os = map.get("OS");
        String browser = map.get("BROWSER");
        String ip = IpUtils.getIpAddr(request);
        user.setLastLoginIp(ip);
        user.setOs(os);
        user.setBrowser(browser);
        user.setLastLoginTime(new Date());
        //从Redis中获取IP来源
        String jsonResult = stringRedisTemplate.opsForValue().get(RedisConf.IP_SOURCE + Constants.SYMBOL_COLON + ip);
        if (StringUtils.isEmpty(jsonResult)) {
            String addresses = IpUtils.getAddresses(ip, "utf-8");
            if (StringUtils.isNotEmpty(addresses)) {
                user.setIpSource(addresses);
                stringRedisTemplate.opsForValue().set(RedisConf.IP_SOURCE + Constants.SYMBOL_COLON + ip, addresses, 24, TimeUnit.HOURS);
            }
        } else {
            user.setIpSource(jsonResult);
        }
        return user;
    }

    // endregion
    /***************************** didiok-web:end **************************/

    /**
     * 登录
     *
     * @param vo
     * @return
     */
    @Override
    public UserEntity login(UserLoginDto vo) {
        String loginacct = vo.getLoginacct();
        String password = vo.getPassword(); //123456

        //1、去数据库查询 SELECT * FROM `ums_member` WHERE username=? OR mobile=?
        UserEntity entity = userDao.selectOne(new QueryWrapper<UserEntity>().eq("userName", loginacct)
                .or().eq("mobile", loginacct));
        if (entity == null) {
            //登录失败
            return null;
        } else {
            //1、获取到数据库的password  $2a$10$2xOI1.2DTQxpWeWd3Rk0qOVPTpauodlYkafTjNb4LOMuS1zBEZc5K
            String passwordDb = entity.getPassword();
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            //2、密码匹配
            boolean matches = passwordEncoder.matches(password, passwordDb);
            if (matches) {
                return entity;
            } else {
                return null;
            }
        }
    }

    /**
     * 注册
     *
     * @param vo
     */
    @Override
    public void regist(UserRegistDto vo) {
        UserEntity entity = new UserEntity();

        //检查用户名和手机号是否唯一。为了让controller能感知异常，异常机制
        checkMobileUnique(vo.getMobile());
        checkUserNameUnique(vo.getUserName());

        entity.setMobile(vo.getMobile());
        entity.setUserName(vo.getUserName());

        entity.setNickname(vo.getUserName());

        //密码要进行加密存储。
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(vo.getPassword());
        entity.setPassword(encode);

        //其他的默认信息


        //保存
        userDao.insert(entity);
    }

    /**
     * 检查手机号是否唯一
     * @param mobile
     * @throws MobileExsitException
     */
    @Override
    public void checkMobileUnique(String mobile) throws MobileExsitException {
        // TODO 自己编写查询语句，加上 limit 1
        Integer count = userDao.selectCount(new QueryWrapper<UserEntity>().eq("mobile", mobile));
        if (count > 0) {
            throw new MobileExsitException();
        }

    }

    /**
     * 检查用户名是否唯一
     * @param userName
     * @throws UserNameExistException
     */
    @Override
    public void checkUserNameUnique(String userName) throws UserNameExistException {
        // TODO 自己编写查询语句，加上 limit 1
        Integer count = userDao.selectCount(new QueryWrapper<UserEntity>().eq("user_name", userName));
        if (count > 0) {
            throw new UserNameExistException();
        }

    }

    /**
     * 第三方登录
     *
     * @param user
     * @return
     */
    @Override
    public UserDto oauthLogin(UserDto user) {
        return null;
    }


    /**
     * 根据用户名获取用户信息
     *
     * @param userName 用户名
     * @return
     */
    @Override
    public UserEntity getByUserName(String userName) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper.eq(SQLConf.USER_NAME, userName).or().eq(SQLConf.EMAIL, userName));
        queryWrapper.last(SysConf.LIMIT_ONE);
        queryWrapper.eq(SysConf.STATUS, StatusEnum.ENABLE);
        return this.getOne(queryWrapper);
    }

    /**
     * 根据用户昵称获取用户信息
     *
     * @param nickname
     * @return
     */
    @Override
    public List<UserEntity> getByNickname(String nickname) {
        QueryWrapper<UserEntity> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like(SQLConf.NICKNAME, nickname);
        userQueryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        return this.list(userQueryWrapper);
    }

    /**
     * 用户脱敏【去除敏感信息】
     *
     * @param item
     */
    @Override
    public UserDto convertUser(UserDto item) {
        UserDto user = new UserDto();
        user.setUid(item.getUid());
        user.setAvatar(item.getAvatar());
        user.setPhotoUrl(item.getPhotoUrl());
        user.setNickname(item.getNickname());
        user.setOccupation(item.getOccupation());
        user.setSummary(item.getSummary());
        user.setCreateTime(item.getCreateTime());
        user.setLoadingValid(item.getLoadingValid());
        user.setStatus(item.getStatus());
        user.setGender(item.getGender());
        user.setUserTag(item.getUserTag());
        user.setCredits(item.getCredits());
        user.setExpValue(item.getExpValue());
        user.setUserLevel(UserLevelEnum.getLvByExpValue(item.getExpValue()).getLevel());
        user.setBackgroundFileUrl(item.getBackgroundFileUrl());
        user.setBackgroundFileUid(item.getBackgroundFileUid());

        // 过滤用户
        String ip = item.getLastLoginIp();
        String ipPossession = redisUtil.get(RedisConf.USER_IP_POSSESSION + Constants.SYMBOL_COLON + user.getUid());
        if (StringUtils.isEmpty(ipPossession) && StringUtils.isNotEmpty(ip)) {
            // ip属地
            ipPossession = IpUtils.getIpPossession(ip);
            // 将信息设置到redis中
            redisUtil.setEx(RedisConf.USER_IP_POSSESSION + Constants.SYMBOL_COLON + user.getUid(), ipPossession, 1, TimeUnit.HOURS);
        }
        user.setUserIpPossession(ipPossession);
        return user;
    }

    /**
     * 设置用户头像, 批量方法
     *
     * @param list
     */
    @Override
    public void setUserAvatar(Collection<UserEntity> list) {
        List<String> fileUidList = new ArrayList<>();
        list.forEach(item -> {
            if (StringUtils.isNotEmpty(item.getAvatar())) {
                fileUidList.add(item.getAvatar());
            }
            if (StringUtils.isNotEmpty(item.getBackgroundFileUid())) {
                fileUidList.add(item.getBackgroundFileUid());
            }
        });
        Map<String, String> pictureMap = fileFeignUtil.fileUidToFileUrlMap(fileUidList);
        for (UserEntity item : list) {
            //获取头像
            if (StringUtils.isNotEmpty(item.getAvatar())) {
                List<String> pictureUidsTemp = StringUtils.changeStringToString(item.getAvatar(), SysConf.FILE_SEGMENTATION);
                List<String> pictureListTemp = new ArrayList<>();
                pictureUidsTemp.forEach(picture -> {
                    if (pictureMap.get(picture) != null && pictureMap.get(picture) != "") {
                        pictureListTemp.add(pictureMap.get(picture));
                    }
                });
                if (pictureListTemp.size() > 0) {
                    item.setPhotoUrl(pictureListTemp.get(0));
                }
            }

            //获取图片
            if (StringUtils.isNotEmpty(item.getBackgroundFileUid())) {
                item.setBackgroundFileUrl(pictureMap.get(item.getBackgroundFileUid()));
            }
        }
    }


    @Override
    public UserEntity insertUserInfo(HttpServletRequest request, String response) {
        Map<String, Object> map = JsonUtils.jsonToMap(response);
        boolean exist = false;
        UserEntity user = new UserEntity();
        Map<String, Object> data = JsonUtils.jsonToMap(JsonUtils.objectToJson(map.get(SysConf.DATA)));
        if (data.get(SysConf.UUID) != null && data.get(SysConf.SOURCE) != null) {
            if (getUserBySourceAndSocialUid(data.get(SysConf.SOURCE).toString(), data.get(SysConf.UUID).toString()) != null) {
                user = getUserBySourceAndSocialUid(data.get(SysConf.SOURCE).toString(), data.get(SysConf.UUID).toString());
                exist = true;
            }
        } else {
            log.error("未获取到uuid或source");
            throw new InsertException(ErrorCode.INSERT_DEFAULT_ERROR, MessageConf.INSERT_DEFAULT_ERROR);
        }

        if (data.get(SysConf.EMAIL) != null) {
            user.setEmail(data.get(SysConf.EMAIL).toString());
        }
        if (data.get(SysConf.AVATAR) != null) {
            user.setAvatar(data.get(SysConf.AVATAR).toString());
        }
        if (data.get(SysConf.NICKNAME) != null) {
            user.setNickname(data.get(SysConf.NICKNAME).toString());
        }
        user.setLoginCount(user.getLoginCount() + 1);
        user.setLastLoginTime(new Date());
        user.setLastLoginIp(IpUtils.getIpAddr(request));
        if (exist) {
            user.updateById();
        } else {
            user.setSocialUid(data.get(SysConf.UUID).toString());
            user.setSource(data.get(SysConf.SOURCE).toString());
            user.setUserName("mg".concat(user.getSource()).concat(user.getSocialUid()));
            //产生(0,999999]之间的随机数
            Integer randNum = (int) (Math.random() * (999999) + 1);
            //进行六位数补全
            String workPassWord = String.format("%06d", randNum);
            user.setPassword(workPassWord);
            user.insert();
        }
        return user;
    }

    @Override
    public List<UserEntity> getUserListByIds(List<String> ids) {
        List<UserEntity> userList = new ArrayList<>();
        if (ids == null || ids.size() == 0) {
            return userList;
        }
        Collection<UserEntity> userCollection = this.listByIds(ids);
        userCollection.forEach(item -> {
            userList.add(item);
        });
        return userList;
    }

    /**
     * 通过id获取用户【携带用户头像和背景图片】
     *
     * @param uid@return
     */
    @Override
    public UserEntity getUserListAndAvatarById(String uid) {

        if (StringUtils.isEmpty(uid)) {
            return new UserEntity();
        }
        UserEntity user = this.getById(uid);
        // 过滤用户敏感信息
        user = this.convertUser(user);
        // 设置用户头像
        user = this.setUserAvatar(user);

        return user;
    }

    @Override
    public List<UserEntity> getUserListWithoutAvatarByIds(Collection<String> ids) {
        List<UserEntity> userList = new ArrayList<>();
        if (ids == null || ids.size() == 0) {
            return userList;
        }
        Collection<UserEntity> userCollection = this.listByIds(ids);
        // 过滤用户敏感信息
        userCollection.forEach(item -> {
            userList.add(this.convertUser(item));
        });

        return userList;
    }


    @Override
    public UserEntity setUserAvatar(UserEntity user) {
        List<UserEntity> userList = new ArrayList<>();
        userList.add(user);
        this.setUserAvatar(userList);
        return userList.get(0);
    }

    @Override
    public Boolean getUserActiveStatus(String userUid) {

        // 判断用户是否被封号
        String userActiveStatus = redisUtil.get(RedisConf.USER_ACTIVE_STATUS + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + userUid);
        // 用户已被封号
        if (com.rede.didiok.common.constant.global.Constants.STR_ZERO.equals(userActiveStatus)) {
            return false;
        } else {
            // redis中没记录
            if (userActiveStatus == null) {
                // 可能更新过状态，需要查库进行确认
                UserEntity user = this.getById(userUid);
                // 用户不存在
                if (user == null) {
                    return false;
                }
                // 再次判断用户是否被封号
                if (com.rede.didiok.common.constant.global.Constants.NUM_ONE == user.getCommentStatus()) {
                    // 未封号
                    redisUtil.setEx(RedisConf.USER_ACTIVE_STATUS + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + user.getUid(), com.rede.didiok.common.constant.global.Constants.STR_ONE, 7, TimeUnit.DAYS);
                    return true;
                } else {
                    // 已封号
                    redisUtil.setEx(RedisConf.USER_ACTIVE_STATUS + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + user.getUid(), com.rede.didiok.common.constant.global.Constants.STR_ZERO, 7, TimeUnit.DAYS);
                    return false;
                }
            }
        }
        return true;
    }


    @Override
    public UserEntity convertUser(UserEntity item) {
        UserEntity user = new UserEntity();
        user.setUid(item.getUid());
        user.setAvatar(item.getAvatar());
        user.setPhotoUrl(item.getPhotoUrl());
        user.setNickname(item.getNickname());
        user.setOccupation(item.getOccupation());
        user.setSummary(item.getSummary());
        user.setCreateTime(item.getCreateTime());
        user.setLoadingValid(item.getLoadingValid());
        user.setStatus(item.getStatus());
        user.setGender(item.getGender());
        user.setUserTag(item.getUserTag());
        user.setCredits(item.getCredits());
        user.setExpValue(item.getExpValue());
        user.setUserLevel(UserLevelEnum.getLvByExpValue(item.getExpValue()).getLevel());
        user.setBackgroundFileUrl(item.getBackgroundFileUrl());
        user.setBackgroundFileUid(item.getBackgroundFileUid());

        // 过滤用户
        String ip = item.getLastLoginIp();
        String ipPossession = redisUtil.get(RedisConf.USER_IP_POSSESSION + Constants.SYMBOL_COLON + user.getUid());
        if (StringUtils.isEmpty(ipPossession) && StringUtils.isNotEmpty(ip)) {
            // ip属地
            ipPossession = IpUtils.getIpPossession(ip);
            // 将信息设置到redis中
            redisUtil.setEx(RedisConf.USER_IP_POSSESSION + Constants.SYMBOL_COLON + user.getUid(), ipPossession, 1, TimeUnit.HOURS);
        }
        user.setUserIpPossession(ipPossession);
        return user;
    }


    @Override
    public void setUserPublishInfo(Collection<UserEntity> list) {
        for (UserEntity user : list) {
            // 获取博客数
            RankMemberDto rankMemberDto = new RankMemberDto();
            rankMemberDto.setCreateUserUid(user.getUid());
            Integer rankMemberCount = rankFeignClient.getRankMemberCount(rankMemberDto);
            user.setRankMemberPublishCount(rankMemberCount);

            // 获取问答数
//            QuestionVO questionVO = new QuestionVO();
//            questionVO.setUserUid(user.getUid());
//            Integer questionPublishCount = questionService.getQuestionCount(questionVO);
//            user.setQuestionPublishCount(questionPublishCount);

            // 获取评论数
//            CommentVO commentVO = new CommentVO();
//            commentVO.setUserUid(user.getUid());
//            Integer commentCount = commentService.getCommentCount(commentVO);
//            user.setCommentPublishCount(commentCount);

            // 获取问答数
            UserMomentDto userMomentDto = new UserMomentDto();
            userMomentDto.setCreateUserUid(user.getUid());
            Integer momentCount = communityFeignClient.getUserMomentCount(userMomentDto.getCreateUserUid());
            user.setMomentPublishCount(momentCount);
        }
    }

    @Override
    public void updateCreditsByUserUid(String userUid, Integer credits) {
        userDao.updateCreditsByUserUid(userUid, credits);
    }

    @Override
    public void updateExpValueByUserUid(String userUid, Integer expValue) {
        userDao.updateExpValueByUserUid(userUid, expValue);
    }

    @Override
    public Integer getUserRank(String userUid, boolean refresh) {
        if (StringUtils.isEmpty(userUid)) {
            log.error("[getUserRank] " + MessageConf.PARAM_INCORRECT);
            throw new QueryException(MessageConf.PARAM_INCORRECT);
        }
        String rankJson = redisUtil.get(RedisConf.LOGIN_TOKEN_KEY + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + userUid);
        if (StringUtils.isNotEmpty(rankJson) && !refresh) {
            return Integer.valueOf(rankJson);
        }
        Integer rank = userDao.getUserRank(userUid);
        if (rank != null) {
            redisUtil.setEx(RedisConf.LOGIN_TOKEN_KEY + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + userUid, JsonUtils.objectToJson(rank), 10, TimeUnit.MINUTES);
        }
        return rank;
    }

    @Override
    public Map<String, UserEntity> getRobotUserList() {
        // 获取机器人列表
        String robotUserListJson = redisUtil.get(RedisConf.ROBOT_USER_LIST);
        List<UserEntity> robotUserList = new ArrayList<>();
        if (StringUtils.isNotEmpty(robotUserListJson)) {
            robotUserList = JsonUtils.jsonToList(robotUserListJson, UserEntity.class);
        } else {
            QueryWrapper<UserEntity> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq(SQLConf.USER_TAG, UserTagEnum.ROBOT.getValue());
            userQueryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
            robotUserList = this.list(userQueryWrapper);
            // 设置头像，过滤敏感信息
            if (robotUserList.size() > 0) {
                setUserAvatar(robotUserList);
                robotUserList = convertUserList(robotUserList);
            }
        }
        if (robotUserList != null && robotUserList.size() > 0) {
            redisUtil.setEx(RedisConf.ROBOT_USER_LIST, JsonUtils.objectToJson(robotUserList), 10, TimeUnit.MINUTES);
        }
        return robotUserList.stream()
                .collect(Collectors.toMap(UserEntity::getUid, Function.identity()));
    }

    @Override
    public String getUserCenterUrl(String userUid) {
        return webSiteUrl + "userCenter?userUid=" + userUid;
    }

    @Override
    public ChatGPTSetting checkRobotReply(String userUid, int userTag) {
        ChatGPTSetting chatGPTSetting = new ChatGPTSetting();
        chatGPTSetting.setBlock(false);
        chatGPTSetting.setOpenRobotReply(false);

        // 获取ChatGPT配置
        String chatGPTSettingJson = adminFeignClient.getSysParamsValueByKey(SysConf.SYS_CHATGPT_SETTING);
        if (StringUtils.isEmpty(chatGPTSettingJson)) {
            chatGPTSetting.setOpenRobotReply(true);
            chatGPTSetting.setBlockMessage("系统配置异常");
            return chatGPTSetting;
        }

        chatGPTSetting = JsonUtils.jsonToPojo(chatGPTSettingJson, ChatGPTSetting.class);
        assert chatGPTSetting != null;

        String countJson = redisUtil.get(RedisConf.CHATGPT_REPLY_COUNT + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + userUid);
        if (StringUtils.isEmpty(countJson)) {
            return chatGPTSetting;
        }
        int count = Integer.parseInt(countJson);
        int limitCount = 0;
        if (userTag == 0) {
            // 普通用户，校验普通次数
            limitCount = chatGPTSetting.getReplyCount();
        } else {
            // vip用户，校验vip次数
            limitCount = chatGPTSetting.getReplyCount();
        }
        chatGPTSetting.setLimitCount(count);
        chatGPTSetting.setBlock(limitCount < count);
        return chatGPTSetting;
    }

    @Override
    public String chatGPTReply(String openID, String message) {

        if (StringUtils.isEmpty(openID)) {
            return ResultUtil.errorWithMessage("请求参数异常");
        }

        // 获取用户信息
        String userJson = redisUtil.get(RedisConf.ACCOUNT_ID_TO_USER + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + openID);
        UserEntity user;
        if (StringUtils.isEmpty(userJson)) {
            QueryWrapper<UserAccountEntity> userAccountQueryWrapper = new QueryWrapper<>();
            userAccountQueryWrapper.eq(SQLConf.ACCOUNT_ID, openID);
            userAccountQueryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
            userAccountQueryWrapper.last(SysConf.LIMIT_ONE);
            UserAccountEntity userAccount = userAccountService.getOne(userAccountQueryWrapper);
            if (userAccount == null) {
                log.error("[chatGPTReply] 账户信息为空, AccountID: {}", openID);
                return ResultUtil.errorWithMessage("该微信暂未在网站进行注册，请先完成微信登录后再继续~");
            }
            user = this.getById(userAccount.getCreateUserUid());
            if (user != null) {
                redisUtil.setEx(RedisConf.ACCOUNT_ID_TO_USER + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + openID, JsonUtils.objectToJson(user), 10, TimeUnit.MINUTES);
            }
        } else {
            user = JsonUtils.jsonToPojo(userJson, UserEntity.class);
        }

        if (user == null) {
            log.error("[chatGPTReply] 用户信息为空, AccountID: {}", openID);
            return ResultUtil.errorWithMessage("未查询到用户信息，请稍后再试");
        }

        // 开始进行机器人回复
        // 获取ChatGPT配置
        ChatGPTSetting chatGPTSetting = this.checkRobotReply(user.getUid(), user.getUserTag());

        String regex = "<a[^>]*>[^<]*<\\/a>";
        String result = message.replaceAll(regex, "");
        Document doc = Jsoup.parse(result);
        String question = doc.text();
        String chatGPTResult = "";
        // 是否开启
        if (chatGPTSetting == null || !chatGPTSetting.isOpenRobotReply()) {
            chatGPTResult = "抱歉，后台暂未开启智能问答，请联系管理员";
        } else {
            // 开启了问答，校验是否还有提问次数
            if (chatGPTSetting.isBlock()) {
                chatGPTResult = "抱歉，今日机器人回复您的次数已达到上限，暂时无法提供问答服务";
            } else {
                chatGPTResult = HttpRequestUtil.askOpenAi(question, chatGPTSetting.getApiUrl(), chatGPTSetting.getApiKey());
                // 没有回复内容，可能内部系统存在问题
                if (StringUtils.isEmpty(chatGPTResult)) {
                    chatGPTResult = "抱歉，网络出现问题，请稍后再试";
                } else {
                    chatGPTResult = chatGPTResult.replaceFirst("\\n", "").replaceFirst("\\n", "");

                    // redis计数器增加
                    redisUtil.setEx(RedisConf.CHATGPT_REPLY_COUNT + com.rede.didiok.common.constant.global.Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(chatGPTSetting.getLimitCount() + 1), 12, TimeUnit.HOURS);
                }
            }
        }
        return ResultUtil.successWithData(chatGPTResult);
    }

    @Override
    public String getUserUidByRequest() {
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isNotEmpty(userUid)) {
            return userUid;
        }

        String adminUid = RequestHolder.getAdminUid();
        if (StringUtils.isEmpty(adminUid)) {
            throw new QueryException("用户未登录");
        }
        // 当为后台管理员添加的时候
        R adminResult = adminFeignClient.getAdminByUid(adminUid);
        AdminDto admin = null;
        if (adminResult.getCode() == 0) {
            admin = adminResult.getData(new TypeReference<AdminDto>(){});
        }else {
            throw new FeignException("feign调用异常（通过 id 获取管理员）：失败");
        }
        if (admin == null) {
            throw new QueryException("管理员状态错误,请重新登录后!");
        }
        // 判断是否附身用户
        if (StringUtils.isEmpty(admin.getUserUid())) {
            throw new QueryException("您暂未附身用户，无法进行操作，请到 管理员管理-> 编辑, 选择要附身用户 再重新操作!");
        }
        return admin.getUserUid();
    }

    @Override
    public void updateAmountByUserUid(String userUid, Long operateAmount) {
        // 如果操作的金额是负数，说明是积分扣除操作，还需要获取用户的当前余额
        UserEntity user = this.getById(userUid);
        if (user == null) {
            throw new UpdateException("无法获取用户信息");
        }
        if (operateAmount < 0) {
            if (user == null) {
                log.error("[updateAmountByUserUid] 暂未查询到该用户，userUid: " + userUid);
                throw new UpdateException("暂未查询到该用户");
            }
            if (user.getAmount() + operateAmount < 0) {
                log.error("[updateAmountByUserUid] 用户钱包余额不足，操作失败，userUid: " + userUid);
                throw new UpdateException("余额不足，操作失败");
            }
        }
        userDao.updateAmountByUserUid(userUid, operateAmount);
    }

    /**
     * 根据用户名找用户
     *
     * @param username
     * @return
     */
    @Override
    public UserEntity getUserByUserName(String username) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper.eq(SQLConf.USER_NAME, username).or().eq(SQLConf.EMAIL, username));
        queryWrapper.last(SysConf.LIMIT_ONE);
        queryWrapper.eq(SysConf.STATUS, StatusEnum.ENABLE);
        UserEntity userEntity = this.getOne(queryWrapper);
        return userEntity;
    }


    /**
     * 获取文章被访问数
     *
     * @param userUid
     * @return
     */
    @Override
    public Integer getRankMemberVisitCount(String userUid) {
        Integer blogVisitCount = 0;
        if (StringUtils.isEmpty(userUid)) {
            return blogVisitCount;
        }

        String blogVisitCountJson = redisUtil.get(RedisConf.RANK_MEMBER_VISIT_COUNT + Constants.SYMBOL_COLON + userUid);
        if (StringUtils.isNotEmpty(blogVisitCountJson)) {
            return Integer.valueOf(blogVisitCountJson);
        }

        R oidResult = rankFeignClient.listIdByUserUidAndSource(userUid,ContributeSourceEnum.USER_PUBLISH);
        List<RankMemberDto> rankMemberDtoList;
        if (oidResult.getCode() == 0) {
            rankMemberDtoList = oidResult.getData(new TypeReference<List<RankMemberDto>>(){});
        }else {
            throw new FeignException("feign调用异常（根据用户id和文章来源，查询文章的oid和Uid）：失败");
        }
        List<String> visitUidList = new ArrayList<>();
        rankMemberDtoList.forEach(item -> {
            visitUidList.add(item.getUid());
        });

        if (visitUidList.size() > 0) {
            QueryWrapper<WebVisitEntity> webVisitQueryWrapper = new QueryWrapper<>();
            // 兼容历史数据
            webVisitQueryWrapper.in(SQLConf.MODULE_UID, visitUidList);
            blogVisitCount = webVisitService.count(webVisitQueryWrapper);
            redisUtil.setEx(RedisConf.RANK_MEMBER_VISIT_COUNT + Constants.SYMBOL_COLON + userUid, JsonUtils.objectToJson(blogVisitCount), 10, TimeUnit.MINUTES);
        }
        return blogVisitCount;
    }

    /**
     * at事件通用处理方法
     *
     * @param userUid
     * @param toUserUid
     * @param toUid
     * @param bizUid
     * @param bizType
     * @param message
     * @param isAt
     * @return
     */
    @Override
    public R atEventHandler(String userUid, String toUserUid, String toUid, String bizUid, String bizType, String message, boolean isAt) {
        // 判断消息中，是否有AT请求
        log.info("消息处理: {}", message);

        // 获取发送的用户信息
        UserEntity user = this.getById(userUid);

        // 判断被AT的是否是机器人
        Map<String, UserEntity> robotUserMap = this.getRobotUserList();
        UserEntity toUser = robotUserMap.get(toUserUid);
        String chatGPTResult = "";
        // 判断是否是机器人回复
        if (toUser != null) {
            // 开始进行机器人回复
            // 获取ChatGPT配置
            ChatGPTSetting chatGPTSetting = this.checkRobotReply(user.getUid(), user.getUserTag());

            String regex = "<a[^>]*>[^<]*<\\/a>";
            String result = message.replaceAll(regex, "");
            Document doc = Jsoup.parse(result);
            String question = doc.text();

            // 是否开启
            if (chatGPTSetting == null || !chatGPTSetting.isOpenRobotReply()) {
                chatGPTResult = "抱歉，后台暂未开启智能问答，请联系管理员";
            } else {
                // 开启了问答，校验是否还有提问次数
                if (chatGPTSetting.isBlock()) {
                    chatGPTResult = "抱歉，今日机器人回复您的次数已达到上限，暂时无法提供问答服务";
                } else {
                    chatGPTResult = HttpRequestUtil.askOpenAi(question, chatGPTSetting.getApiUrl(), chatGPTSetting.getApiKey());
                    // 没有回复内容，可能内部系统存在问题
                    if (StringUtils.isEmpty(chatGPTResult)) {
                        chatGPTResult = "抱歉，网络出现问题，请稍后再试";
                    } else {
                        chatGPTResult = chatGPTResult.replaceFirst("\\n", "").replaceFirst("\\n", "");

                        // redis计数器增加
                        redisUtil.setEx(RedisConf.CHATGPT_REPLY_COUNT + Constants.SYMBOL_COLON + user.getUid(), JsonUtils.objectToJson(chatGPTSetting.getLimitCount() + 1), 12, TimeUnit.HOURS);
                    }
                }
            }

            // 将markdown替换
            chatGPTResult = FileUtils.markdownToHtml(chatGPTResult);
            // 构造评论，进行回复
            if(CommentSourceEnum.RANK_MEMBER_INFO.getCode().equals(bizType)){

                MemberCommentDto comment = new MemberCommentDto();
                comment.setToUid(toUid);
                comment.setSource(bizType);
                comment.setMemberUid(bizUid);
                comment.setCreateUserUid(toUser.getUid());
                comment.setContent(chatGPTResult);
                comment.setAuditStatus(AuditStatusEnum.AGREE);
                comment.setAuditName("系统");
                comment.setAuditTime(new Date());
                comment.setToUserUid(user.getUid());
                R commentResult = rankFeignClient.addCommentWithFirstCommentUid(comment);
                if (commentResult.getCode() == 0) {
                    comment = commentResult.getData(new TypeReference<MemberCommentDto>(){});
                }else {
                    throw new FeignException("feign调用异常（添加榜单成员评论:当该评论不是一级评论时，需要设置一级评论UID字段）：失败");
                }

                // 发送评论对应的通知
                noticeService.sendNoticeByMemberComment(comment);
            }else if(CommentSourceEnum.USER_MOMENT.getCode().equals(bizType)){

                MomentCommentDto comment = new MomentCommentDto();
                comment.setToUid(toUid);
                comment.setSource(bizType);
                comment.setMomentUid(bizUid);
                comment.setCreateUserUid(toUser.getUid());
                comment.setContent(chatGPTResult);
                comment.setAuditStatus(AuditStatusEnum.AGREE);
                comment.setAuditName("系统");
                comment.setAuditTime(new Date());
                comment.setToUserUid(user.getUid());
                R commentResult = communityFeignClient.addCommentWithFirstCommentUid(comment);
                if (commentResult.getCode() == 0) {
                    comment = commentResult.getData(new TypeReference<MomentCommentDto>(){});
                }else {
                    throw new FeignException("feign调用异常（添加用户动态评论:当该评论不是一级评论时，需要设置一级评论UID字段）：失败");
                }

                // 发送评论对应的通知
                noticeService.sendNoticeByMomentComment(comment);
            }

            return R.ok();
        }

        // 不是AT请求，不记录AT通知
        if (!isAt) {
            return R.ok();
        }

        // 不是机器人，可能是AT的普通用户，需要给用户发送通知
        // 记录被AT的通知
        NoticeDto noticeVO = new NoticeDto();
        noticeVO.setNoticeType(NoticeTypeEnum.SYSTEM.getCode());
        ResourceTypeEnum resourceType = ResourceTypeEnum.getResourceByComment(bizType);
        BusinessTypeEnum businessType = ResourceTypeEnum.resourceType2BusinessType(resourceType, 3);
        noticeVO.setBusinessType(businessType.getCode());
        noticeVO.setBusinessUid(bizUid);
        noticeVO.setCreateUserUid(toUserUid);
        noticeVO.setContent(message);
        noticeVO.setIsBack(0);
        noticeService.addNotice(noticeVO);

        // 记录小红点
        String redisKey = RedisConf.USER_RECEIVE_SYSTEM_NOTICE_COUNT + Constants.SYMBOL_COLON + toUserUid;
        String count = redisUtil.get(redisKey);
        if (StringUtils.isNotEmpty(count)) {
            redisUtil.incrBy(redisKey, Constants.NUM_ONE);
        } else {
            redisUtil.setEx(redisKey, Constants.STR_ONE, 7, TimeUnit.DAYS);
        }
        return R.ok();
    }
}